package com.example.ormsqlsplicingframe1.session;

import com.example.ormsqlsplicingframe1.note.ConditionEnum;
import com.example.ormsqlsplicingframe1.note.JoinQuery;
import com.example.ormsqlsplicingframe1.note.JoinWhere;
import com.example.ormsqlsplicingframe1.orm.registry.*;
import com.example.ormsqlsplicingframe1.sql.Sql;
import com.example.ormsqlsplicingframe1.utlis.GetGenerics;
import com.example.ormsqlsplicingframe1.utlis.ImportTypeUtils;
import com.example.ormsqlsplicingframe1.utlis.ObjValue;
import com.example.ormsqlsplicingframe1.warpper.SelectSqlWrapper;
import lombok.SneakyThrows;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;


public class ProxySession  extends BaseSession {


    public ProxySession(DataSource datasource) {
        super(datasource);
        importType(new RegistryDate()).importType(new RegistryBoolean()).importType(new RegistryDouble())
                .importType(new RegistryInteger()).importType(new RegistryLong()).importType(new RegistryString()).importType(new RegistryList()).importType(new RegistryLocalDate());
    }

    //级联加载对象  cascadeLoadingField 当前对象的字段
    @SneakyThrows
    private void fillAllField(Object e){

        if (e != null){
            Class<?> eClass = e.getClass();

            Map<String, Field> map = Arrays.stream(eClass.getDeclaredFields()).distinct().collect(Collectors.toMap(field -> field.getName(), field -> field));

            for (Field field : eClass.getDeclaredFields()) {

                JoinQuery query = field.getAnnotation(JoinQuery.class);
                if (query != null && field.getType() != Object.class){
                    //从级联加载直接上获取字段，根据字段名去获取对应的字段值
                    Field cascadeLoadingField = map.get(query.value());
                    if (cascadeLoadingField != null){
                    cascadeLoadingField.setAccessible(true);
                    field.setAccessible(true);

                        Object value = cascadeLoadingField.get(e);
                        if (value != null && !value.equals("")){
                            if (field.getType() == List.class){

                                Type genericType = field.getGenericType();
                                if (null == genericType) continue;
                                if (genericType instanceof ParameterizedType) {
                                    ParameterizedType pt = (ParameterizedType) genericType;
                                    // 得到泛型里的class类型对象
                                    Class<?> actualTypeArgument = (Class<?>)pt.getActualTypeArguments()[0];


                                    //得到类型就去查询
                                    List selectList = (List) SelectSqlWrapper.newSelectSqlWrapper(actualTypeArgument).where(wh -> {

                                        if (field.getType() == List.class){
                                            wh.in(query.primary(),   GetGenerics.objToList(value));
                                        }else {
                                            wh.eq(query.primary(), value);
                                        }

                                        if (query.wheres().length>0){

                                            wh.or(or ->{
                                                for (JoinWhere where : query.wheres()) {
                                                    if (where.and()){
                                                        if (where.condition() == ConditionEnum.eq){
                                                            wh.eq(where.name(),where.value());
                                                        }
                                                        if (where.condition() == ConditionEnum.in){
                                                            wh.in(where.name(),Arrays.stream(where.value().split(",")).collect(Collectors.toList()));
                                                        }
                                                        if (where.condition() == ConditionEnum.ne){
                                                            wh.ne(where.name(),where.value());
                                                        }
                                                    }else {
                                                        if (where.condition() == ConditionEnum.eq){
                                                            or.eq(where.name(),where.value());
                                                        }
                                                        if (where.condition() == ConditionEnum.in){
                                                            or.in(where.name(),Arrays.stream(where.value().split(",")).collect(Collectors.toList()));
                                                        }
                                                        if (where.condition() == ConditionEnum.ne){
                                                            or.ne(where.name(),where.value());
                                                        }
                                                    }
                                                }
                                            });
                                        }
                                    }).selectList();
                                    // 得到值拷贝返回给字段
                                    if (selectList.size()>0){
                                        field.set(e, selectList);
                                    }
                                }
                            }else {

                                Object obj =  SelectSqlWrapper.newSelectSqlWrapper(field.getType()).where(wh -> {
                                    if (query.condition() == ConditionEnum.eq){
                                        wh.eq(query.primary(), value);
                                    }
                                    if (query.condition() == ConditionEnum.ne){
                                        wh.ne(query.primary(), value);
                                    }

                                }).selectOnt();
                                if (ObjValue.isNotNull(obj)){
                                    field.set(e, obj);
                                }

                            }
                        }else {
                            field.set(e, null);
                        }

                    }
                }
            }
        }
    }


    @Override
    protected void before(Sql sql) {
        //
        super.before(sql);
    }

    @Override
    protected Object after(Sql sql, Object data) {
        //
        if(data instanceof List){
            List list = (List)data;
            for (Object o : list) {
                fillAllField(o);
            }
        }
        if (data instanceof Object){
            fillAllField(data);
        }
        return super.after(sql, data);
    }

    private ImportTypeUtils  importTypeUtils = ImportTypeUtils.newInstance();

    public  ProxySession importType(Registry registry){
        importTypeUtils.put(registry.getObj(),registry);
        return this;
    }



    @SneakyThrows
    public  Object decode(String value, Field field){

        Registry registry = importTypeUtils.get(field.getType());

        if (registry == null && field.getType() instanceof Object){
            return field.getType().newInstance();
        }

        if (registry == null){
            throw new RuntimeException("类型不兼容:"+field.getType());
        }

        return registry.decode(value,field);

    }

    public  Object encode(Object value){

        if (value.getClass() == String.class){
            return value;
        }
        if (value.getClass().isPrimitive()){
            return value;
        }
        if (value.getClass() == Integer.class){
            return value;
        }
        if (value.getClass() == Date.class){
            return value;
        }
        if (value.getClass() == Long.class) {
            return value;
        } else  {
            throw new RuntimeException("当前类型不匹配:"+value.getClass());
        }

    }

}
